﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;

namespace LFSRecord2.Misc
{
    public class EndianMemoryMappedFile : IDisposable
    {
        MemoryMappedFile _mmf;
        public MemoryMappedViewAccessor _accessor;

        long _position = 0;
        public long Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public long Length { get; private set; }

        /// <summary>
        /// Indicates whether the stream uses big or little endian
        /// </summary>
        public bool IsLittleEndian { get; private set; }
        byte[] buf = new byte[8];

        /// <summary>
        /// Initialises a new instance of the EndianMemoryMappedFile class with the specified path.
        /// </summary>
        /// <param name="path">The absolute path to the file</param>
        /// <param name="mode">FileMode indicator</param>
        /// <param name="endian">Endian indicator</param>
        public EndianMemoryMappedFile(string path, EndianTypes endian)
        {
            _mmf = MemoryMappedFile.CreateFromFile(path);
            CreateViewAccessor();
            IsLittleEndian = endian == EndianTypes.Little;
        }
        ~EndianMemoryMappedFile()
        {
            Dispose(true);
        }
        public void Dispose()
        {
            Dispose(true);
        }
        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_accessor != null)
                {
                    _accessor.Flush();
                    _accessor.Dispose();
                    _accessor = null;
                }
                if (_mmf != null)
                    _mmf.Dispose();
                GC.SuppressFinalize(this);
            }
        }

        public void CreateViewAccessor()
        {
            ReleaseAccessor();
            _accessor = _mmf.CreateViewAccessor();
            Position = 0;
            Length = _accessor.Capacity;
        }

        public void CreateViewAccessor(long offset, long size)
        {
            ReleaseAccessor();
            _accessor = _mmf.CreateViewAccessor(offset, size);
            Position = 0;
            Length = _accessor.Capacity;
        }

        public void ReleaseAccessor()
        {
            if (_accessor != null)
            {
                _accessor.Flush();
                _accessor.Dispose();
                _accessor = null;
            }
        }

        public char[] ReadAnsiChars(int size)
        {
            char[] c = new char[size];
            for (int a = 0; a < size; a++)
            {
                c[a] = (char)_accessor.ReadByte(Position++);
            }
            return c;
        }

        public int ReadInt32()
        {
            Position += 4;
            return _accessor.ReadInt32(Position - 4);
        }

        public void ReadBytes(byte[] array, int offset, int count)
        {
            count += offset;
            if (IsLittleEndian)
            {
                count--;
                for (int a = count; a >= offset; a--)
                {
                    array[a] = _accessor.ReadByte(Position++);
                }
            }
            else
            {
                for (int a = offset; a < count; a++)
                {
                    array[a] = _accessor.ReadByte(Position++);
                }
            }
        }

        public byte ReadByte()
        {
            return _accessor.ReadByte(Position++);
        }

        public ushort ReadUInt16()
        {
            Position += 2;
            return _accessor.ReadUInt16(Position - 2);
        }

        public uint ReadUInt32()
        {
            Position += 4;
            return _accessor.ReadUInt32(Position - 4);
        }
    }
}
